#include<iostream>

#include<stdio.h>

#include<pthread.h>

#include<unistd.h>

#include<string>

#include<vector>

#include<time.h>

#include<queue>

// using namespace std;

enum
{
    zero = -1,
    unknow = -2
};

char OP[] = "+-*/%";

struct thread_info
{
    thread_info(const std::string& str, int n)
    {
        _name = str + std::to_string(n);
    }
    std::string _name;
    pthread_t _PT;
};

template<class T>
class thread_pool
{
    typedef thread_pool<T> Thread_Pool;
    static void* Solution(void* arg)
    {
        Thread_Pool* self = static_cast<Thread_Pool*>(arg);
        while(1)
        {
            usleep(1000);
            T get = self->pop();
            get(self->GetThreadName(pthread_self()));
        }
        return nullptr;
    }

    std::string GetThreadName(pthread_t tid)
    {
        for(auto& e : _arr)
            if(e._PT == tid) return e._name;
        return "NONE";
    }

public:
    thread_pool()
    {
        pthread_mutex_init(&_mt, nullptr);
        pthread_cond_init(&push_cd, nullptr);
        pthread_cond_init(&pop_cd, nullptr);
    }

    ~thread_pool()
    {
        pthread_mutex_destroy(&_mt);
        pthread_cond_destroy(&push_cd);
        pthread_cond_destroy(&pop_cd);

        for(auto& e : _arr)
            pthread_join(e._PT, nullptr);
    }

    void start()
    {
        for(int i = 0; i < _max; ++i)
        {
            _arr.push_back(thread_info("thread-", i));
            pthread_create(&(_arr[i]._PT), nullptr, Solution, (void*)this);
        }
    }

    void push(const T& tk)
    {
        pthread_mutex_lock(&_mt);

        while(_qu.size() >= _max)
        {
            pthread_cond_wait(&push_cd, &_mt);
        }
        _qu.push(tk);

        pthread_cond_broadcast(&pop_cd);
        pthread_mutex_unlock(&_mt);
    }

    T pop()
    {
        pthread_mutex_lock(&_mt);

        while(_qu.size() <= 0)
        {
            pthread_cond_wait(&pop_cd, &_mt);
        }

        T ret = _qu.front();

        _qu.pop();

        pthread_cond_broadcast(&push_cd);
        pthread_mutex_unlock(&_mt);

        return ret;
    }

private:
    int _max = 5;
    std::vector<thread_info> _arr;
    std::queue<T> _qu;
    pthread_mutex_t _mt;
    pthread_cond_t push_cd;
    pthread_cond_t pop_cd;
};

// int main()
// {
//     srand(time(nullptr));
//     thread_pool<task> tp;
//     tp.start();

//     while(1)
//     {
//         usleep(1000);
//         task tk(rand() % 10, rand() % 10, OP[rand() % 5]);

//         tk.print();
//         tp.push(tk);
//     }
//     return 0;
// }